package com.fresh.bus.chat.business;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;
import javax.mail.internet.MimeMessage;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;

import com.fresh.bus.canoe.message.Response;
import com.fresh.bus.canoe.session.Session;
import com.fresh.bus.canoe.session.SessionRoleManager;
import com.fresh.bus.chat.ctrl.OpCodes;
import com.fresh.bus.chat.domain.AssoLog;
import com.fresh.bus.chat.domain.UserLog;
import com.fresh.bus.chat.persist.MessageDao;
import com.fresh.bus.chat.persist.UserDao;
import com.fresh.bus.chat.util.DateUtil;

@Component
public class FriendService {
	private static final Logger log = LoggerFactory
			.getLogger(FriendService.class);
	private static final Logger userLog = LoggerFactory.getLogger("userLog");
	@Resource
	private JavaMailSenderImpl javaMailSender;
	private ObjectMapper objectMapper = new ObjectMapper();

	@Resource
	private UserDao dao;
	@Resource
	private MessageDao msgDao;
	@Resource
	private UserService userService;
	@Resource
	private AssoValueService assoValueService;
	@Resource
	private MessageService msgService;
	@Resource
	private WealthService wealthService;
	@Resource
	private TreeService treeService;
	@Resource
	protected SessionRoleManager roleManager;

	private StringRedisTemplate template;

	@Autowired
	public FriendService(StringRedisTemplate template) {
		this.template = template;
	}

	public Map<String, String> addFriend(Integer from, Integer to,
			String nikeName) throws Exception {
		String fStr = String.valueOf(from);
		String tStr = String.valueOf(to);

		List<Map<String, Object>> list = dao.findFriendsByUser(from);
		if (list.size() >= UserService.MAX_FRIEND_AMT) {
			throw new Exception("意中人总数不能超过" + UserService.MAX_FRIEND_AMT + "个");
		}

		if (!this.friend(fStr, tStr).isEmpty()) {
			throw new Exception("对方已在关注者列表了");
		}

		dao.addFriend(nikeName, from, to, 0);
		Map<String, Object> map = dao.findFriend(from, to);
		this.createInMem(map);

		assoValueService.update(fStr, tStr, AssoLog.FOLLOW_USER, "0");
		// msgService.notifyTargetUser(tStr, fStr, UserLog.FOLLOW_USER, "0");
		return this.friend(fStr, tStr);
	}

	private void createInMem(Map<String, Object> friend) {
		String from = String.valueOf(friend.get("from_user"));
		String to = String.valueOf(friend.get("to_user"));

		String fid = KeyUtils.asso(from, to);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(fid);
		ops.put("id", to);
		ops.put("nikeName", (String) friend.get("nike_name"));
		ops.put("assoValue", String.valueOf(friend.get("asso_value")));
		int level = (Integer) friend.get("level");
		ops.put("level", String.valueOf(level));
		int upgradeExp = this.assoValueService.getUpgradeExp(level);
		ops.put("upgradeExp", String.valueOf(upgradeExp));
		ops.put("eventLog", String.valueOf(friend.get("event_log")));

		Date now = new Date();
		int i = DateUtil.getDaysBetween((Date) friend.get("visite_at"), now);
		ops.put("canHello", "true");// 每人每天只能打一次招呼
		ops.put("visitDays", String.valueOf(i));
		int j = DateUtil.getDaysBetween((Date) friend.get("created_at"), now);
		ops.put("beginDays", String.valueOf(j));

		BoundHashOperations<String, String, String> u = template
				.boundHashOps(KeyUtils.uid(to));
		if (u.size() > 0) {
			String visitDate = u.get("latestVisit");
			if (visitDate == null) {
				visitDate = DateUtil.convertDateToString(new Date());
			}
			ops.put("latestVisitAt", visitDate);
		}

		if (this.roleManager.getSession(to) != null) {
			ops.put("online", "true");
		}
	}

	public boolean removeFriend(Integer from, Integer to) {
		String friendKey = KeyUtils.asso(String.valueOf(from),
				String.valueOf(to));
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(friendKey);
		log.info("User[" + from + "] is removing friend[" + to + "]");
		template.delete(friendKey);
		dao.removeFriend(from, to);
		return true;
	}

	public int upgradeAsso(String from, String to) {
		String friendKey = KeyUtils.asso(from, to);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(friendKey);
		int level = Integer.valueOf(ops.get("level"));
		level++;
		ops.put("level", String.valueOf(level));
		ops.put("assoValue", "0");
		int upgradeExp = this.assoValueService.getUpgradeExp(level);
		ops.put("upgradeExp", String.valueOf(upgradeExp));
		this.assoValueService.update(from, to, AssoLog.LEVEL_UPGRADE,
				String.valueOf(level));
		return level;
	}

	public int writeMessage(String from, String to, String content,
			boolean isReply) throws Exception {
		BoundHashOperations<String, String, String> u = template
				.boundHashOps(KeyUtils.uid(from));
		int permitAmt = u.get("permitWord") == null ? UserService.DAILY_WORD_AMT
				: Integer.valueOf(u.get("permitWord"));

		if (!isReply) {
			// 扣除每日发送配额
			permitAmt--;
			if (permitAmt < 0) {
				return -1;
				// throw new Exception("今日可留言数已用完!更多留言需等明日。");
			} else {
				u.put("permitWord", String.valueOf(permitAmt));
			}
		}
		int dbId = msgDao.writeMsg(from, to, content);
		String dbStr = String.valueOf(dbId);
		if (!isReply) {
			this.assoValueService.update(from, to, AssoLog.ADD_WORDS, dbStr); // 记录日志
		}
		// notifyTargetUser(to, dbId, to, from, content);// 通知目标对象
		msgService.notifyTargetUser(to, from, UserLog.LIUYAN, dbStr);
		return permitAmt;
	}

	public List<Map<String, Object>> readHistory(String u1, String u2) {
		return msgDao.readHistory(u1, u2);
	}

	public void sayHello(String from, String to) {
		assoValueService.update(from, to, AssoLog.SAY_HELLO, "0");
		msgService.notifyTargetUser(to, from, UserLog.SAY_HELLO, "0");
	}

	public boolean reqFriend(String from, String to, int flowerAmt)
			throws Exception {
		boolean flag = false;
		String level = "";
		String assoValue = "";

		flag = this.wealthService.giveFlower(from, to, flowerAmt);
		if (flag) {
			Map<String, String> map = this.friend(from, to);
			if (map.isEmpty()) {
				map = addFriend(Integer.valueOf(from), Integer.valueOf(to),
						"用户" + to);
				wealthService.update(1, WealthService.ADD_GUANZHU, to);
			} else {
				level = map.get("level");
				assoValue = map.get("assoValue");
			}
			msgService.notifyTargetUser(to, from, UserLog.REQ_FRIEND,
					String.valueOf(flowerAmt) + "*" + level + "*" + assoValue);
		}
		return flag;
	}

	public boolean acceptFriend(String from, String to, int level)
			throws Exception {
		Map<String, String> map = this.getAsso(to,from);
		if (map.isEmpty()) {
			map = addFriend(Integer.valueOf(to), Integer.valueOf(from), "用户"
					+ from);
			wealthService.update(1, WealthService.ADD_GUANZHU, from);
		} else {
			int curLevel = Integer.valueOf(map.get("level"));
			if (curLevel < level) {
				int tarLevel = upgradeAsso(to, from);
				msgService.notifyTargetUser(to, from, UserLog.ACCEPT_FRIEND,
						String.valueOf(tarLevel));
			}
		}
		return true;
	}

	public void inviteLevelUp(String from, String to) {
		msgService.notifyTargetUser(to, from, UserLog.REQ_LEVEL_UP, "0");
	}

	public void inviteNewTree(String from, String to) {
		msgService.notifyTargetUser(to, from, UserLog.REQ_NEW_TREE, "0");
	}

	public boolean inviteGiveWater(String from, String to) {
		Map<String, Object> tmap = this.treeService.getTree(from);
		if (!tmap.isEmpty()) {
			sendMailForNeddWater(to);
			msgService.notifyTargetUser(to, from, UserLog.REQ_WATER, "0");
		}
		return !tmap.isEmpty();
	}

	// 邮件通知需要清水
	private void sendMailForNeddWater(String userId) {
		Map<String, String> u = this.userService.findUser(userId);
		String qqNo = u.get("qqNo");
		Date today = new Date();
		Date latestDay = DateUtil.convertStringToDate(u.get("latestVisit"));
		int offsetDay = DateUtil.getDaysBetween(latestDay, today);

		if (qqNo != null && qqNo.trim().length() > 4 && offsetDay > 2) {
			MimeMessage mimeMessage = javaMailSender.createMimeMessage();
			MimeMessageHelper helper = new MimeMessageHelper(mimeMessage);
			try {
				helper.setFrom("myfreshcity@163.com", "脱单名片");
				helper.setTo(qqNo + "@qq.com");
				helper.setSubject("【脱单名片】美女用户 " + userId + " 正求你送些清水，快来帮她！");
				helper.setText(
						"<p>美女用户  "
								+ userId
								+ " 用来浇灌梧桐树的存水池已经空了。<br/>她正发出邀请，求你帮帮她采些清水。<a style=\"color:#0000FF;text-decoration: none;\" href=\"http://rc.qzone.qq.com/100711253\" target=\"_blank\">&nbsp;&nbsp;&gt;&gt;前去帮她</a></p>",
						true);
				javaMailSender.send(mimeMessage);
			} catch (Exception e) {
				log.error("Send user[" + qqNo + "] mail failed...",
						e.getMessage());
			}
		}
	}

	public void thankWater(String from, String to) {
		msgService.notifyTargetUser(to, from, UserLog.THANK_WATER, "0");
	}

	public Map<String, String> friend(String id, String to) {
		BoundHashOperations<String, String, String> userOps = template
				.boundHashOps(KeyUtils.asso(id, to));
		return userOps.entries();

	}

	public Map<String, String> getAsso(String id, String to) {
		Map<String, String> map = this.friend(id, to);
		if (map.isEmpty()) {
			Map<String, Object> asso = dao.findFriend(Integer.valueOf(id),
					Integer.valueOf(to));
			this.createInMem(asso);
		}
		map = this.friend(id, to);
		return map;
	}

	public void setFriendCond(Map<String, String> data, String user) {
		String uid = KeyUtils.uid(user);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(uid);
		String content;
		try {
			content = objectMapper.writeValueAsString(data);
			ops.put("cond", content);
		} catch (Exception e) {
			log.error("set friend cond failed:" + user, e);
		}
	}

	public void setQQNo(String qqNo, String user) {
		String uid = KeyUtils.uid(user);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(uid);
		ops.put("qqNo", qqNo);
	}

	@SuppressWarnings("unchecked")
	public Map<String, String> getFriendCond(String id) {
		String uid = KeyUtils.uid(id);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(uid);
		try {
			String condStr = ops.get("cond");
			if (condStr != null && condStr.length() > 0) {
				return this.objectMapper.readValue(condStr, Map.class);
			}
		} catch (Exception e) {
			log.error("get friend condition faild:" + id, e);
		}
		return new HashMap<String, String>();
	}

	public String getQQNo(String about, String mine) throws Exception {
		String uid = KeyUtils.uid(mine);
		BoundHashOperations<String, String, String> ops = template
				.boundHashOps(uid);
		// 校验当日配额
		int permitAmt = ops.get("permitQQNo") == null ? UserService.DAILY_QQNO_AMT
				: Integer.valueOf(ops.get("permitQQNo"));

		if (permitAmt <= 0) {
			throw new Exception("今日名额已用完，明日再来或给TA留言。");
		}

		Map<String, String> user = this.userService.findUser(about);
		// 校验个人条件
		String msg = validFriendCond(user.get("cond"), ops.entries());
		if (msg != null) {
			throw new Exception(msg);
		}

		permitAmt--;
		ops.put("permitQQNo", String.valueOf(permitAmt));
		String content = String.valueOf(mine);
		String qqNo = ops.get("qqNo");
		msgService.notifyTargetUser(about, content, UserLog.GET_QQ, qqNo);
		return user.get("qqNo");
	}

	public String validFriendCond(String condStr, Map<String, String> mine) {
		String msg = null;
		try {
			Map<String, String> cond = this.objectMapper.readValue(condStr,
					Map.class);
			Calendar cal = Calendar.getInstance();
			int year = cal.get(Calendar.YEAR);
			int yearFrom = Integer.valueOf(cond.get("ageFrom"));
			int yearTo = Integer.valueOf(cond.get("ageTo"));
			int myYear = year - Integer.valueOf(mine.get("birthYear"));
			if (myYear < yearFrom || myYear > yearTo) {
				return "年龄不在对方的择友范围";
			}

			if (cond.get("addProv") != null && cond.get("addCity") != null) {
				String location = cond.get("addProv") + "-"
						+ cond.get("addCity");
				if (location != null && location.length() > 0) {
					String myLocation = mine.get("location");
					if (myLocation.indexOf(location) == -1) {
						return "居住地不在对方的择友范围";
					}
				}
			}

			if (cond.get("tallFrom") != null && cond.get("tallTo") != null) {
				String tallFrom = cond.get("tallFrom");
				String tallTo = cond.get("tallTo");

				if (tallFrom != null && tallTo != null) {
					int tFrom = Integer.valueOf(cond.get("tallFrom"));
					int tTo = Integer.valueOf(cond.get("tallTo"));
					int myTall = Integer.valueOf(mine.get("tall"));
					if (myTall < tFrom || myTall > tTo) {
						return "身高不在对方的择友范围";
					}
				}
			}

			// 友好度校验，暂缺
			// 学历校验，暂缺
		} catch (Exception e) {
			log.error("validFriendCond failed...", e);
		}
		return msg;
	}

	public List<Map<String, String>> queryFriends(String id) {
		List<Map<String, String>> result = new ArrayList<Map<String, String>>();
		List<Map<String, Object>> list = dao.findFriendsByUser(Integer
				.valueOf(id));

		for (Map<String, Object> friend : list) {
			createInMem(friend);
			// ops.put("visiteAt", DateUtil.convertDateToString(visit_at));
			String to = String.valueOf(friend.get("to_user"));
			Map<String, String> f = this.friend(id, to);
			result.add(f);
		}
		return result;
	}

	public List<Map<String, String>> queryFans(String id) {
		List<Map<String, String>> result = new ArrayList<Map<String, String>>();
		List<Map<String, Object>> list = dao
				.findFansByUser(Integer.valueOf(id));
		String fid = null;
		for (Map<String, Object> u : list) {
			fid = String.valueOf(u.get("id"));
			result.add(userService.findUser(fid));
		}
		return result;
	}
}
